# -*- coding: utf-8 -*-
import docx
from docx import Document
from docx.shared import Pt, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
import os
import sys
from PyQt5.QtWidgets import QApplication, QFileDialog

# --- 定义样式名称常量 ---
STYLE_NORMAL = '正文'
STYLE_HEADING_1 = '标题 1'
STYLE_HEADING_2 = '标题 2'
STYLE_HEADING_3 = '标题 3'
STYLE_TITLE = '大标题'

# --- 辅助函数 (保持不变或微调) ---
def get_file_path(title="选择文件", file_filter="All Files (*)", save_mode=False, initial_dir=None):
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    options = QFileDialog.Options()
    file_path = None
    if not save_mode:
        file_path, _ = QFileDialog.getOpenFileName(None, title, initial_dir if initial_dir else "", file_filter, options=options)
    else:
        file_path, _ = QFileDialog.getSaveFileName(None, title, initial_dir if initial_dir else "", file_filter, options=options)
    if not file_path:
        return None
    return file_path

def set_paragraph_format(paragraph, alignment=WD_ALIGN_PARAGRAPH.JUSTIFY, first_line_indent=True,
                         space_before=0, space_after=0, line_spacing=28):
    """
    设置段落格式。
    注意：这些设置会直接写入段落XML，可能覆盖样式中的部分格式。
    """
    paragraph.alignment = alignment # 这会覆盖样式中的对齐
    paragraph_format = paragraph.paragraph_format
    paragraph_format.space_before = Pt(space_before)
    paragraph_format.space_after = Pt(space_after)
    paragraph_format.line_spacing_rule = docx.enum.text.WD_LINE_SPACING.EXACTLY
    paragraph_format.line_spacing = Pt(line_spacing)

    if first_line_indent:
        paragraph_format.first_line_indent = Pt(2 * 10.5)
    else:
        paragraph_format.first_line_indent = Pt(0)

def set_font_chinese(run_or_font_obj, font_name):
    """
    正确设置中文字体。
    添加一些调试打印来确认函数执行。
    """
    # print(f"Debug: Setting font for object: {type(run_or_font_obj)}")
    try:
        element = run_or_font_obj._element if hasattr(run_or_font_obj, '_element') else getattr(run_or_font_obj, 'element', None)
        if element is None:
             print("Error: Could not find element for font setting.")
             return
        rPr = element.rPr
        if rPr is None:
            rPr = OxmlElement('w:rPr')
            element.append(rPr)

        eastAsia = rPr.find(qn('w:eastAsia'))
        if eastAsia is None:
            eastAsia = OxmlElement('w:eastAsia')
            rPr.append(eastAsia)

        eastAsia.set(qn('w:val'), font_name)
        # print(f"Debug: Set eastAsia font to {font_name}")

        # 同时设置 run.font.name
        if hasattr(run_or_font_obj, 'font') and hasattr(run_or_font_obj.font, 'name'):
            run_or_font_obj.font.name = font_name
        elif hasattr(run_or_font_obj, 'name'):
            run_or_font_obj.name = font_name
    except Exception as e:
         print(f"Error in set_font_chinese: {e}")

def set_font(run, name, size):
    run.font.size = size
    set_font_chinese(run, name)

# --- 核心函数：创建和应用样式 (关键修改点) ---
def create_styles(doc):
    """
    在文档中创建或更新符合规范的样式。
    强制重新定义样式，确保使用最新的设置。
    """
    styles = doc.styles

    # --- 强制删除旧样式 (如果存在) ---
    # 这样可以确保每次都使用最新的定义
    for style_name in [STYLE_NORMAL, STYLE_HEADING_1, STYLE_HEADING_2, STYLE_HEADING_3, STYLE_TITLE]:
        if style_name in styles:
            try:
                # print(f"Debug: Removing existing style {style_name}")
                styles._element.remove(styles[style_name]._element) # 直接从XML移除
                # styles.__delitem__(style_name) # 另一种尝试，但可能不稳定
            except Exception as e:
                 print(f"Warning: Could not remove style {style_name}: {e}")
                 # 如果删除失败，add_style 通常会覆盖

    # --- 正文样式 ---
    # 移除了 'if STYLE_NORMAL not in styles:' 检查
    style_normal = styles.add_style(STYLE_NORMAL, docx.enum.style.WD_STYLE_TYPE.PARAGRAPH)
    style_normal.base_style = styles['Normal']
    set_font_chinese(style_normal.font, '方正仿宋简体')
    style_normal.font.size = Pt(16)
    # 为正文样式也设置段落格式，使其更完整
    set_paragraph_format(style_normal.paragraph_format) # 应用默认正文段落格式到样式本身

    # --- 一级标题样式 "一、" ---
    # 移除了 'if STYLE_HEADING_1 not in styles:' 检查
    style_h1 = styles.add_style(STYLE_HEADING_1, docx.enum.style.WD_STYLE_TYPE.PARAGRAPH)
    set_font_chinese(style_h1.font, '方正黑体简体')
    style_h1.font.size = Pt(16)
    # 为标题样式设置段落格式
    set_paragraph_format(style_h1.paragraph_format, first_line_indent=False, space_after=10) # 示例：标题后加点间距

    # --- 二级标题样式 "（一）" ---
    # 移除了 'if STYLE_HEADING_2 not in styles:' 检查
    style_h2 = styles.add_style(STYLE_HEADING_2, docx.enum.style.WD_STYLE_TYPE.PARAGRAPH)
    set_font_chinese(style_h2.font, '方正楷体简体')
    style_h2.font.size = Pt(16)
    set_paragraph_format(style_h2.paragraph_format, first_line_indent=False, space_after=8) # 示例

    # --- 三级标题样式 "1." ---
    # 移除了 'if STYLE_HEADING_3 not in styles:' 检查
    style_h3 = styles.add_style(STYLE_HEADING_3, docx.enum.style.WD_STYLE_TYPE.PARAGRAPH)
    set_font_chinese(style_h3.font, '方正仿宋简体')
    style_h3.font.bold = True
    style_h3.font.size = Pt(16)
    set_paragraph_format(style_h3.paragraph_format, first_line_indent=False, space_after=6) # 示例

    # --- 大标题样式 ---
    # 移除了 'if STYLE_TITLE not in styles:' 检查
    style_title = styles.add_style(STYLE_TITLE, docx.enum.style.WD_STYLE_TYPE.PARAGRAPH)
    set_font_chinese(style_title.font, '方正小标宋简体')
    style_title.font.size = Pt(22)
    # 注意：大标题的段落格式直接在样式中设置，避免后续 set_paragraph_format 覆盖
    style_title.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
    style_title.paragraph_format.space_after = Pt(12) # 示例：大标题后间距

def is_file_locked(filepath):
    if not os.path.exists(filepath):
        return False
    try:
        with open(filepath, 'r+'):
            pass
        return False
    except PermissionError:
        return True
    except OSError:
        return True
    except Exception:
        return True

def main():
    print("--- Word 一键排版程序 ---")

    # --- 文件选择 (省略部分代码以缩短示例) ---
    input_file_path = get_file_path(title="选择原始 Word 文档", file_filter="Word Files (*.docx);;All Files (*)", save_mode=False)
    if input_file_path: print(f"已选择输入文件: {input_file_path}")
    default_output_name = "排版后_" + os.path.basename(input_file_path) if input_file_path else "新排版文档.docx"
    default_output_dir = os.path.dirname(input_file_path) if input_file_path else os.getcwd()
    base_output_path = os.path.join(default_output_dir, os.path.splitext(default_output_name)[0])
    output_file_path = get_file_path(title="保存排版后的 Word 文档", file_filter="Word Files (*.docx)", save_mode=True, initial_dir=base_output_path)
    if not output_file_path:
        print("未选择输出文件路径或操作已取消，程序退出。")
        sys.exit(1)
    else:
        if not output_file_path.lower().endswith('.docx'): output_file_path += '.docx'
        print(f"已选择输出文件: {output_file_path}")

    # --- 加载或创建文档 ---
    doc = Document(input_file_path) if input_file_path and os.path.exists(input_file_path) else Document()
    if input_file_path and os.path.exists(input_file_path): print(f"已加载文档: {input_file_path}")

    # --- 设置页面边距 ---
    for section in doc.sections:
        section.top_margin = Cm(3.7)
        section.bottom_margin = Cm(3.5)
        section.left_margin = Cm(2.8)
        section.right_margin = Cm(2.6)
    print("已设置页面边距。")

    # --- 创建/更新样式 ---
    create_styles(doc)
    print("已创建/更新文档样式。") # 修改提示信息

    # --- 应用样式到段落 (关键修改部分) ---
    if input_file_path and os.path.exists(input_file_path):
        print("正在应用段落格式到现有内容...")
        for i, paragraph in enumerate(doc.paragraphs):
            text = paragraph.text.strip()
            if not text:
                continue

            # --- 应用样式 (使用字符串名称) ---
            # 默认应用正文样式
            paragraph.style = STYLE_NORMAL
            # 注意：这里不再调用 set_paragraph_format(paragraph) 因为样式中已经包含了段落格式
            # 如果需要微调，可以在应用特定样式后调用

            # 识别并应用标题样式
            if i == 0:
                print(f"识别到第一段，应用大标题样式: {text}")
                paragraph.style = STYLE_TITLE
                # 大标题样式已包含居中等设置

            elif any(text.startswith(prefix) for prefix in ['一、', '二、', '三、', '四、', '五、', '六、', '七、', '八、', '九、', '十、']):
                print("识别到一级标题")
                paragraph.style = STYLE_HEADING_1
                # 一级标题样式已包含无首行缩进等设置
            elif text.startswith('（') and '）' in text[:5]:
                print("识别到二级标题")
                paragraph.style = STYLE_HEADING_2
                # 二级标题样式已包含无首行缩进等设置
            elif text[0].isnumeric() and len(text) > 2 and text[1] == '.' and text[2] == ' ': # 更严格的检查
                print("识别到三级标题")
                paragraph.style = STYLE_HEADING_3
                # 三级标题样式已包含无首行缩进等设置

            # --- 不再需要显式的 else 块来应用正文样式 ---
            # 因为我们已经在循环开始时 `paragraph.style = STYLE_NORMAL` 了
            # 并且标题识别是用 elif，所以只有非标题段落会保留正文样式

        print("段落格式应用完成。")

    # --- 添加落款 (示例，注意样式应用方式) ---
    print("正在添加示例落款...")
    for _ in range(3): doc.add_paragraph()
    # 创建段落时直接应用样式，然后调整段落格式
    unit_para = doc.add_paragraph("某某单位", style=STYLE_NORMAL) # 创建时应用样式
    unit_para.alignment = WD_ALIGN_PARAGRAPH.CENTER # 调整对齐
    # 不再调用 set_paragraph_format(unit_para, first_line_indent=False) 因为样式已定义
    # 如果样式中正文需要首行缩进，而落款不需要，可以在样式应用后调整
    unit_para.paragraph_format.first_line_indent = Pt(0) # 显式取消缩进

    date_para = doc.add_paragraph("2023年10月27日", style=STYLE_NORMAL) # 创建时应用样式
    date_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT # 调整对齐
    date_para.paragraph_format.right_indent = Pt(8 * 10.5) # 调整右缩进
    date_para.paragraph_format.first_line_indent = Pt(0) # 显式取消缩进

    print("示例落款添加完成。")

    # --- 保存文档 ---
    print(f"正在保存文档到: {output_file_path}")
    if is_file_locked(output_file_path):
        print(f"警告: 文件 '{output_file_path}' 可能正被另一个程序打开。请关闭该文件后再尝试保存。")
        input("请关闭文件后按 Enter 键继续...")
    try:
        doc.save(output_file_path)
        print(f"文档已成功保存到: {output_file_path}")
        print("--- 排版完成 ---")
    except Exception as e:
        print(f"保存文档时出错: {e}")
        sys.exit(1)

if __name__ == "__main__":
    import os
    import sys
    from contextlib import redirect_stderr

    # --- 第一步：设置 Qt 日志规则 ---
    os.environ['QT_LOGGING_RULES'] = 'qt.png*=false;*.warning=false;*.critical=false'


    def safe_file_dialog():
        app = QApplication.instance() or QApplication(sys.argv)

        # --- 第二步：临时屏蔽 stderr ---
        with open(os.devnull, 'w') as fnull:
            with redirect_stderr(fnull):
                from PyQt5.QtWidgets import QFileDialog
                files, _ = QFileDialog.getOpenFileNames(
                    caption="选择文件",
                    filter="Word 文档 (*.docx)"
                )
        return files


    # 使用
    files = safe_file_dialog()
    print(f"选中文件: {files}")

    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


